#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>          /* See NOTES */
#include<sys/socket.h>
#include<strings.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include <unistd.h>
#include<string.h>

#define N 32  //在这里定义最大的name为32字节，用户名不能超过32字节

#define R 1   //定义user->register
#define L 2   //定义user->login
#define Q 3   //定义user->query查询
#define H 4   //定义user->history查询历史记录



//定义通信双方的信息结构体
typedef struct{
    int type;
    char name[N];
    char data[256]; //传输的数据最大字节数为256字节
}MSG;


int do_register(int sockfd,MSG *msg){
    msg->type=R;
    printf("请输入名字:");
    scanf("%s",msg->name); // 在这里因为msg本身就是指针，也就是已经指向相应的内存地址了，不需要加上&地址符了
    getchar();
    printf("请输入密码：");
    scanf("%s",msg->data);

    if(send(sockfd,msg,sizeof(MSG),0)<0){
        printf("fail to send.\n");
        return -1;
    }

    if(recv(sockfd,msg,sizeof(MSG),0)<0){
        printf("fail to recv.\n");
        return -1;
    }
    // 表示注册已经成功
    printf("%s\n",msg->data);

    return 0;  //没有返回值，但是告诉操作系统这个函数已经运行完毕了

}


int do_login(int sockfd,MSG *msg){   //return 1 means login sucessfully,return 0 means login unsucessfully
    msg->type=L;
    printf("请输入名字:");
    scanf("%s",msg->name); // 在这里因为msg本身就是指针，也就是已经指向相应的内存地址了，不需要加上&地址符了
    getchar();
    printf("请输入密码：");
    scanf("%s",msg->data);

    if(send(sockfd,msg,sizeof(MSG),0)<0){
        printf("fail to send.\n");
        return -1;
    }

    if(recv(sockfd,msg,sizeof(MSG),0)<0){
        printf("fail to recv.\n");
        return -1;
    }

    if(strncmp(msg->data,"OK",3)==0){   //OK+'\0'
        printf("login ok!\n");
        return 1;   //return 1 means login sucessfully
    }else{
        printf("%s\n",msg->data);
    }
    return 0;
}

int do_query(int sockfd,MSG *msg){
    msg->type=Q;
    puts("--------------");
    while(1){
        printf("Input word:");
        scanf("%s",msg->data);
        getchar();
        //输入#的时候，返回上一级菜单
        if(strncmp(msg->data,"#",1)==0){
            break;  //跳出while()循环，回到next当中的循环
        }
        //将要查询的单词发送给服务器
        if(send(sockfd,msg,sizeof(MSG),0)<0){
            printf("fail to send\n");
            return -1;
        }

        //等待接收服务器传回来的信息
        if(recv(sockfd,msg,sizeof(MSG),0)<0){
            printf("fail to receive\n");
            return -1;
        }

        printf("%s\n",msg->data);

    }
    return 0;
}

int do_history(int sockfd,MSG *msg){
    msg->type=H;
    send(sockfd,msg,sizeof(MSG),0);

    //接收服务器，传递回来的历史记录信息
    while(1){
        recv(sockfd,msg,sizeof(MSG),0);
        if(msg->data[0]=='\0'){
            break;
        }
        //输出历史记录信息
        printf("%s\n",msg->data);
    }

    return 0;
}

int main(int argc,const char *argv[]){

    int sockfd;  //创建socket套接字的文件描述符
    struct sockaddr_in serveraddr;
    int n;   //从终端当中读出数据
    MSG msg;

    if(argc!=3){
        printf("错误： %s 未传入正确的ip地址和端口号，正确的命令行格式举例:./client 192.168.3.196 1000\n",argv[0]);
        return -1; //传回参数错误标志
    }

    if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0){
        perror("socket过程发生错误");
        return -1; //main函数运行终止
    }

    bzero(&serveraddr,sizeof(serveraddr));

    serveraddr.sin_family=AF_INET;
    serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
    serveraddr.sin_port=htons(atoi(argv[2]));  //atio在这里表示将字符串转化为整形变量

    if(connect(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0){
        perror("fail to connect!!!");
        return -1;
    }

    while(1){
        printf("********************************\n");
        printf("**1.regiter   2.login    3.quit*\n");
        printf("********************************\n");
        printf("please choose the above options!!!\n");
        scanf("%d",&n);
        getchar();  //将输入的其他垃圾字符去掉，因为在输入的过程当中有可能出现输入了其他字符的可能

        switch(n){
            case 1:
                do_register(sockfd,&msg);
                break;
            case 2:
                if(do_login(sockfd,&msg)==1){
                    goto next;
                }
                break;
            case 3:
                close(sockfd);
                exit(0);//正常退出
                break;
            default:
                printf("非法的输入，请输入1、2、3,也就是上面的选项\n");
                //记住在这里我们不需要break，因为输入了非法字符我们还是可以循环再进入下一次输入的

        }
    }

next:
    while(1){
        printf("****************************************\n");
        printf("*1.query_word  2.history_record  3.quit*\n");
        printf("****************************************\n");
        printf("please choose the above options!!!\n");
        scanf("%d",&n);
        getchar();

        switch(n){
            case 1:
                do_query(sockfd,&msg);
                break;
            case 2:
                do_history(sockfd,&msg);
                break;
            case 3:
                close(sockfd);
                exit(0);
                break;
            default:
                printf("非法的输入，请输入1、2、3,也就是上面的选项\n");

        }
    }


    return 0;
}